using System;
using System.Threading;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.NotificationServices;

namespace OracleInternal.ServiceObjects
{
	internal class OracleONSNotificationManager
	{
		private string m_serviceName = string.Empty;

		private const string EvntTypeForService = "(\"eventType=database/event/service\")";

		private const string EvntTypeForHost = "(\"eventType=database/event/host\")";

		private bool m_bListeningOnDefaultNodes;

		internal static OracleONSNotificationManager GetNotificationManager(NotificationType type)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.GetNotificationManager);
			}
			try
			{
				return type switch
				{
					NotificationType.HA => new OracleHANotificationManager(), 
					NotificationType.RLB => new OracleRLBNotificationManager(), 
					NotificationType.ChunkMove => new OracleChunkNotificationManager(), 
					_ => throw new InvalidOperationException(), 
				};
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.GetNotificationManager);
				}
			}
		}

		internal void RegisterForNotification(string serviceName, string databaseName, int timeout, string eventTypeFromDb, string onsConfigFromDb)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.RegisterForNotification);
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.SvcObj, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.RegisterForNotification, $"(serviceName={serviceName}) (databaseName={databaseName}) (timeout={timeout}) (eventTypeFromDb={eventTypeFromDb}) (onsConfigFromDb={onsConfigFromDb})");
			}
			try
			{
				m_serviceName = serviceName;
				string text = string.Empty;
				string empty = string.Empty;
				if (ConfigBaseClass.m_ONSMode == OnsConfigMode.remote)
				{
					text = ProviderConfig.GetONSConfiguration(databaseName);
					if (!m_bListeningOnDefaultNodes)
					{
						if (!string.IsNullOrWhiteSpace(ConfigBaseClass.m_nodeListFromConfFile))
						{
							text.IndexOf('\n');
							text = text + "," + ConfigBaseClass.m_nodeListFromConfFile;
						}
						m_bListeningOnDefaultNodes = true;
					}
				}
				else if (ConfigBaseClass.m_ONSMode == OnsConfigMode.local)
				{
					text = "nodes.list=127.0.0.1:" + ProviderConfig.GetPropertyFromONSConfig(ConfigBaseClass.m_ONSConfigFile, ConfigInfo.ONSRemotePort);
				}
				if (!string.IsNullOrEmpty(onsConfigFromDb))
				{
					string text2 = text;
					text = onsConfigFromDb.Trim().TrimEnd(new char[1]);
					if (!string.IsNullOrEmpty(text2))
					{
						int num = text.IndexOf("nodes.");
						if (num != -1)
						{
							int num2 = text.IndexOf('\n', num);
							if (num2 == -1)
							{
								num2 = text.Length;
							}
							text2 = text2.Split('=')[1];
							text = text.Insert(num2, "," + text2);
						}
						else
						{
							text += text2;
						}
					}
				}
				empty = GetEventTypeForNotification(eventTypeFromDb, m_serviceName);
				long num3 = 0L;
				if (timeout <= 0)
				{
					num3 = 15000L;
				}
				else
				{
					num3 = timeout * 1000;
					if (num3 > int.MaxValue)
					{
						num3 = 2147483647L;
					}
				}
				Subscriber subscriber = new ONS(text).createNewSubscriber(empty, "", num3);
				if (subscriber == null)
				{
					throw new SubscriptionException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ONS_SUBSCR_FAILED));
				}
				Thread thread = new Thread(new ParameterizedThreadStart(StartSubscription));
				thread.IsBackground = true;
				thread.Start(subscriber);
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.RegisterForNotification, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.RegisterForNotification);
				}
			}
		}

		private void StartSubscription(object subscriberObj)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.StartSubscription);
			}
			try
			{
				Notification notification = null;
				Subscriber subscriber = (Subscriber)subscriberObj;
				try
				{
					while (true)
					{
						notification = subscriber.receive(blocking: true);
						if (notification != null)
						{
							ThreadPool.QueueUserWorkItem(new WaitCallback(HandleEvent), notification);
						}
					}
				}
				catch (Exception ex)
				{
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)268697600, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.StartSubscription, "ONS::StartSubscription() . -" + ex.Message);
					}
					subscriber.close();
				}
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleONSNotificationManager, OracleTraceFuncName.StartSubscription);
				}
			}
		}

		protected virtual string GetEventTypeForNotification(string eventTypeFromDb, string serviceName)
		{
			throw new InvalidOperationException();
		}

		protected virtual void HandleEvent(object notification)
		{
			throw new InvalidOperationException();
		}
	}
}
